#include "system/system.hpp"
#include <iterator>
#include <type_traits>
#include "core/assert.hpp"
#include "core/timespan.hpp"
#include "system/system_private.hpp"

void ISystem::pre_tick() { /* nothing by default */ }
void ISystem::after_tick() { /* nothing by default */ }

static ISystem* systems[256][8] {}; // 最多拥有 256*8个系统，256个优先级，每个优先级8个系统

void register_system(ISystem *system)
{
    PI_ASSERT(system != nullptr);
    u8 const priority = system->tick_priority();
    // find first empty slot
    u8 empty_slot = 0;
    while (systems[priority][empty_slot] != nullptr && empty_slot < std::size(*systems))
        ++empty_slot;
    PI_ASSERT_MSG(empty_slot != std::size(*systems), "NO Empty Slot Avaliable!!");
    systems[priority][empty_slot] = system;
}

void unregister_system(ISystem *system)
{
    PI_ASSERT(system != nullptr);
    u8 const priority = system->tick_priority();
    
    // find my location
    u8 slot = 0;
    while(slot < std::size(*systems) && systems[priority][slot] != system) { ++slot; }
    PI_ASSERT(slot < std::size(*systems));

    // erase
    systems[priority][slot] = nullptr;

    // find last not empty
    u8 not_empty = std::size(*systems) - 1;
    while(not_empty > slot && systems[priority][not_empty] == nullptr) { --not_empty; }

    // swap if my location in middle
    if (not_empty > slot) {
        std::swap(systems[priority][slot], systems[priority][not_empty]);
    }
}

void pre_tick_systems()
{
    for (u32 i=0; i<std::size(systems); ++i) {
        for (u8 j=0; j<std::size(*systems); ++j) {
            if (!systems[i][j]) {
                break; // 后面再无实例
            }
            systems[i][j]->pre_tick();
        }
    }
}

void tick_systems(pi_time_t delta, pi_time_t time)
{
    for (u32 i=0; i<std::size(systems); ++i) {
        for (u8 j=0; j<std::size(*systems); ++j) {
            if (!systems[i][j]) {
                break; // 后面再无实例
            }
            systems[i][j]->on_tick(delta, time);
        }
    }
}

void after_tick_systems()
{
    for (u32 i=0; i<std::size(systems); ++i) {
        for (u8 j=0; j<std::size(*systems); ++j) {
            if (!systems[i][j]) {
                break; // 后面再无实例
            }
            systems[i][j]->after_tick();
        }
    }
}
